interface Todo2 {
  title: string;
  description: string;
}
type MyReadonly<T> = {
  readonly [P in keyof T]: T[P];
};
const todo2: MyReadonly<Todo2> = {
  title: "Hey",
  description: "foobar",
};

todo2.title = "Hello"; // Error: cannot reassign a readonly property
todo2.description = "barFoo"; // Error: cannot reassign a readonly property

// ---------------------------------------------------------------------
// 对象部分属性只读
interface Todo {
  title: string;
  description: string;
  completed: boolean;
}
// Omit 会创建一个省略 K 中字段的 T 对象。
type MyOmit<T, K extends keyof T> = { [P in MyExclude<keyof T, K>]: T[P] };

type MyReadonly2<T, K extends keyof T = keyof T> = MyOmit<T, K> &
  Readonly<Pick<T, K>>;
const todo1: MyReadonly2<Todo, "title" | "description"> = {
  title: "Hey",
  description: "foobar",
  completed: false,
};

todo1.title = "Hello"; // Error: cannot reassign a readonly property
todo1.description = "barFoo"; // Error: cannot reassign a readonly property
todo1.completed = true; // OK
